﻿


#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <stdbool.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>  // 新增locale头文件

#define WIDTH 60
#define HEIGHT 30
#define INIT_LENGTH 4
#define SLEEP_BASE 200
#define MAX_INPUT_LEN 64
#define MAX_RETRY 1000

// 控制台颜色属性
enum COLORS {
    COLOR_BLUE = FOREGROUND_BLUE,
    COLOR_GREEN = FOREGROUND_GREEN,
    COLOR_RED = FOREGROUND_RED,
    COLOR_YELLOW = FOREGROUND_RED | FOREGROUND_GREEN,
    COLOR_CYAN = FOREGROUND_BLUE | FOREGROUND_GREEN,
    COLOR_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
};

// 方向枚举
enum DIRECTION { UP, RIGHT, DOWN, LEFT };

// 蛇结构体
typedef struct SnakeNode {
    COORD pos;
    struct SnakeNode* next;
} Snake;

// 双缓冲结构
typedef struct {
    CHAR_INFO buffer[HEIGHT][WIDTH];
    HANDLE hOutput;
    COORD bufferSize;
    COORD bufferCoord;
    SMALL_RECT writeRegion;
} ConsoleBuffer;

ConsoleBuffer g_buffer;
Snake* snake = NULL;
COORD food;
int direction = RIGHT;
int score = 0;
int highest_score = 0;
int sleeptime = SLEEP_BASE;
bool game_running = true;

// 函数声明
void initConsoleBuffer();
void clearBuffer();
void renderBuffer();
void setBufferChar(int x, int y, wchar_t ch, WORD attr);
void initGame();
void createMap();
void drawSnake();
void createFood();
void moveSnake();
void checkCollision();
void updateScore();
void gameOver();
void saveScore();
void welcomeScreen();
void showExplanation();
void setCursorPos(int x, int y);
bool bitesSelf();
bool hitWall();
void speedUp();
void speedDown();
void keyboardControl();
void initSnake();
void safeExit(int code);
int safeInput(int min, int max);
void loadHighScore();
void clearSnake();

// 初始化双缓冲
void initConsoleBuffer() {
    g_buffer.hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleOutputCP(CP_UTF8);
    g_buffer.bufferSize.X = WIDTH;
    g_buffer.bufferSize.Y = HEIGHT;
    g_buffer.bufferCoord.X = 0;
    g_buffer.bufferCoord.Y = 0;
    g_buffer.writeRegion = { 0, 0, WIDTH - 1, HEIGHT - 1 };

    // 设置控制台窗口大小
    SetConsoleWindowInfo(g_buffer.hOutput, TRUE, &g_buffer.writeRegion);

    // 设置控制台字体
    CONSOLE_FONT_INFOEX cfi = { sizeof(cfi) };
    GetCurrentConsoleFontEx(g_buffer.hOutput, FALSE, &cfi);
    wcscpy_s(cfi.FaceName, L"Consolas");
    SetCurrentConsoleFontEx(g_buffer.hOutput, FALSE, &cfi);
}



// 清空缓冲区
void clearBuffer() {
    for (int y = 0; y < HEIGHT; y++) {
        for (int x = 0; x < WIDTH; x++) {
            g_buffer.buffer[y][x].Char.UnicodeChar = L' ';
            g_buffer.buffer[y][x].Attributes = 0;
        }
    }
}

// 渲染缓冲区
void renderBuffer() {
    WriteConsoleOutput(
        g_buffer.hOutput,
        (CHAR_INFO*)g_buffer.buffer,
        g_buffer.bufferSize,
        g_buffer.bufferCoord,
        &g_buffer.writeRegion
    );
}

// 设置缓冲区字符
void setBufferChar(int x, int y, wchar_t ch, WORD attr) {
    if (x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT) {
        g_buffer.buffer[y][x].Char.UnicodeChar = ch;
        g_buffer.buffer[y][x].Attributes = attr;
    }
}

// 安全退出函数
void safeExit(int code) {
    clearSnake();
    exit(code);
}

// 清理蛇数据
void clearSnake() {
    Snake* current = snake;
    while (current != NULL) {
        Snake* temp = current;
        current = current->next;
        free(temp);
    }
    snake = NULL;
}

// 设置光标位置
void setCursorPos(int x, int y) {
    COORD coord = { x, y };
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

// 安全输入函数
int safeInput(int min, int max) {
    char input[MAX_INPUT_LEN] = { 0 };
    char* endptr;
    long value;

    while (1) {
        setCursorPos(0, HEIGHT + 1);
        if (fgets(input, sizeof(input), stdin) == NULL) {
            continue;
        }

        value = strtol(input, &endptr, 10);

        if (endptr == input || *endptr != '\n') {
            printf("无效输入，请输入数字 (%d-%d): ", min, max);
            continue;
        }

        if (value < min || value > max) {
            printf("输入超出范围 (%d-%d): ", min, max);
            continue;
        }

        return (int)value;
    }
}

void initSnake() {
    clearSnake();

    int startX = 24 + 2 * INIT_LENGTH;
    int startY = 5;
    int step = 2;

    snake = (Snake*)malloc(sizeof(Snake));
    if (!snake) safeExit(EXIT_FAILURE);
    snake->pos.X = startX;
    snake->pos.Y = startY;
    snake->next = NULL;

    Snake* current = snake;
    for (int i = 1; i <= INIT_LENGTH; i++) {
        Snake* new_node = (Snake*)malloc(sizeof(Snake));
        if (!new_node) safeExit(EXIT_FAILURE);

        new_node->pos.X = startX - step * i;
        new_node->pos.Y = startY;
        new_node->next = NULL;

        current->next = new_node;
        current = new_node;
    }
}

// 读取最高分
void loadHighScore() {
    FILE* file;
    if (fopen_s(&file, "save.txt", "r") == 0 && file != NULL) {
        fscanf_s(file, "%d", &highest_score);
        fclose(file);
    }
}

// 保存最高分
void saveScore() {
    if (score > highest_score) {
        FILE* file;
        if (fopen_s(&file, "save.txt", "w") == 0 && file != NULL) {
            fprintf(file, "%d", score);
            fclose(file);
        }
    }
}

// 创建食物
void createFood() {
    srand((unsigned)time(NULL));
    int attempts = 0;
    bool valid = false;

    while (!valid && attempts < MAX_RETRY) {
        valid = true;
        food.X = (rand() % (WIDTH / 2 - 2)) * 2 + 2;
        food.Y = rand() % (HEIGHT - 2) + 1;

        Snake* current = snake;
        while (current != NULL) {
            if (current->pos.X == food.X && current->pos.Y == food.Y) {
                valid = false;
                break;
            }
            current = current->next;
        }
        attempts++;
    }

    if (!valid) safeExit(EXIT_FAILURE);
}

// 绘制游戏地图
void createMap() {
    for (int y = 0; y < HEIGHT; y++) {
        for (int x = 0; x < WIDTH; x += 2) {
            if (y == 0 || y == HEIGHT - 1 || x == 0 || x == WIDTH - 2) {
                setBufferChar(x, y, L'■', COLOR_BLUE | FOREGROUND_INTENSITY);
            }
        }
    }
}

// 绘制蛇身
void drawSnake() {
    if (!snake) return;

    // 绘制蛇头（红色闪烁）
    setBufferChar(snake->pos.X, snake->pos.Y, L'●',
        COLOR_YELLOW | FOREGROUND_INTENSITY);

    // 绘制渐变蛇身
    Snake* current = snake->next;
    int colorStep = 0;
    while (current) {
        WORD color = COLOR_YELLOW |
            ((colorStep % 3 == 0) ? COLOR_RED : 0) |
            ((colorStep % 2 == 0) ? FOREGROUND_INTENSITY : 0);

        setBufferChar(current->pos.X, current->pos.Y,
            (colorStep % 2) ? L'■' : L'□', color);

        current = current->next;
        colorStep++;
    }
}

// 移动蛇
void moveSnake() {
    COORD new_head = snake->pos;
    switch (direction) {
    case UP:    new_head.Y--; break;
    case DOWN:  new_head.Y++; break;
    case LEFT:  new_head.X -= 2; break;
    case RIGHT: new_head.X += 2; break;
    }

    Snake* new_node = (Snake*)malloc(sizeof(Snake));
    if (!new_node) safeExit(EXIT_FAILURE);
    new_node->pos = new_head;
    new_node->next = snake;
    snake = new_node;

    if (new_head.X == food.X && new_head.Y == food.Y) {
        score += 10;
        createFood();
    }
    else {
        Snake* current = snake;
        while (current->next->next) current = current->next;
        free(current->next);
        current->next = NULL;
    }
}

// 碰撞检测
bool hitWall() {
    COORD head = snake->pos;
    return head.X <= 0 || head.X >= WIDTH - 2 ||
        head.Y <= 0 || head.Y >= HEIGHT - 1;
}

bool bitesSelf() {
    Snake* current = snake->next;
    while (current) {
        if (snake->pos.X == current->pos.X &&
            snake->pos.Y == current->pos.Y) return true;
        current = current->next;
    }
    return false;
}

void checkCollision() {
    if (hitWall() || bitesSelf()) {
        game_running = false;
    }
}

// 速度控制
void speedUp() {
    if (sleeptime > 50) {
        sleeptime -= 30;
        score += 2;
    }
}

void speedDown() {
    if (sleeptime < 350) {
        sleeptime += 30;
        score = score > 2 ? score - 2 : 1;
    }
}

// 键盘控制
void keyboardControl() {
    if (GetAsyncKeyState(VK_UP) & 0x8000 && direction != DOWN) direction = UP;
    if (GetAsyncKeyState(VK_DOWN) & 0x8000 && direction != UP) direction = DOWN;
    if (GetAsyncKeyState(VK_LEFT) & 0x8000 && direction != RIGHT) direction = LEFT;
    if (GetAsyncKeyState(VK_RIGHT) & 0x8000 && direction != LEFT) direction = RIGHT;
    if (GetAsyncKeyState(VK_F1) & 0x8000) speedUp();
    if (GetAsyncKeyState(VK_F2) & 0x8000) speedDown();
    if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) game_running = false;
}

// 更新分数显示
void updateScore() {
    char scoreText[64];
    snprintf(scoreText, sizeof(scoreText), "当前得分: %-6d", score);
    for (int i = 0; i < strlen(scoreText); i++) {
        setBufferChar(WIDTH + 5 + i, 5, scoreText[i], COLOR_WHITE);
    }

    snprintf(scoreText, sizeof(scoreText), "最高得分: %-6d", highest_score);
    for (int i = 0; i < strlen(scoreText); i++) {
        setBufferChar(WIDTH + 5 + i, 6, scoreText[i], COLOR_WHITE);
    }
}
// 游戏欢迎界面
void welcomeScreen() {
    clearBuffer();

    // 使用宽字符版的艺术字
    const wchar_t* snakeArt[] = {
        L"   ██████  ██▓███   ██▀███   ██▓ ██▓███  ▄▄▄█████▓",
        L" ▒██    ▒ ▓██░  ██▒▓██ ▒ ██▒▓██▒▓██░  ██▒▓  ██▒ ▓▒",
        L" ░ ▓██▄   ▓██░ ██▓▒▓██ ░▄█ ▒▒██▒▓██░ ██▓▒▒ ▓██░ ▒░",
        L"   ▒   ██▒▒██▄█▓▒ ▒▒██▀▀█▄  ░██░▒██▄█▓▒ ▒░ ▓██▓ ░ ",
        L" ▒██████▒▒▒██▒ ░  ░░██▓ ▒██▒░██░▒██▒ ░  ░  ▒██▒ ░ ",
        L" ▒ ▒▓▒ ▒ ░▒▓▒░ ░  ░░ ▒▓ ░▒▓░░▓  ▒▓▒░ ░  ░  ▒ ░░   ",
        L" ░ ░▒  ░ ░░▒ ░       ░▒ ░ ▒░ ▒ ░░▒ ░         ░    ",
        L" ░  ░  ░  ░░         ░░   ░  ▒ ░░░         ░      ",
        L"       ░             ░      ░                    "
    };

    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < wcslen(snakeArt[i]); j++) {
            setBufferChar(j, i + 3, snakeArt[i][j], COLOR_YELLOW);
        }
    }

    // 绘制菜单（宽字符版）
    const wchar_t* menu[] = {
        L"1. 开始游戏",
        L"2. 游戏说明",
        L"3. 退出游戏"
    };

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < wcslen(menu[i]); j++) {
            setBufferChar(20 + j, 15 + i * 2, menu[i][j], COLOR_CYAN);
        }
    }

    renderBuffer();
}

// 游戏说明界面
void showExplanation() {
    clearBuffer();

    const wchar_t* explanation[] = {
        L"=== 游戏说明 ===",
        L"1. 使用方向键控制蛇的移动",
        L"2. 吃掉食物（★）可增长身体",
        L"3. 碰撞墙壁或自身游戏结束",
        L"4. F1加速（+2分），F2减速（-2分）",
        L"5. ESC键可随时退出游戏"
    };

    for (int i = 0; i < 6; i++) {
        for (int j = 0; j < wcslen(explanation[i]); j++) {
            setBufferChar(10 + j, 5 + i, explanation[i][j], COLOR_GREEN);
        }
    }

    renderBuffer();
    _getch();
}


// 初始化游戏
void initGame() {
    clearSnake();
    score = 0;
    direction = RIGHT;
    sleeptime = SLEEP_BASE;
    game_running = true;
    loadHighScore();
    initSnake();
    createFood();
}

// 游戏结束界面
void gameOver() {
    clearBuffer();

    // 使用宽字符字符串
    const wchar_t* title = L"=== 游戏结束 ===";
    for (int i = 0; i < wcslen(title); i++) {
        setBufferChar(20 + i, 5, title[i], COLOR_RED);
    }

    // 分数显示
    wchar_t scoreText[64];
    swprintf(scoreText, sizeof(scoreText) / sizeof(wchar_t), L"最终得分: %d", score);
    for (int i = 0; i < wcslen(scoreText); i++) {
        setBufferChar(20 + i, 7, scoreText[i], COLOR_WHITE);
    }

    // 最高分提示
    wchar_t highScoreText[64];
    if (score > highest_score) {
        swprintf(highScoreText, sizeof(highScoreText) / sizeof(wchar_t),
            L"新纪录! 最高分已更新!");
    }
    else {
        swprintf(highScoreText, sizeof(highScoreText) / sizeof(wchar_t),
            L"距离最高分还差: %d", highest_score - score);
    }
    for (int i = 0; i < wcslen(highScoreText); i++) {
        setBufferChar(20 + i, 8, highScoreText[i], COLOR_YELLOW);
    }

    // 菜单选项
    const wchar_t* options[] = { L"1. 重新开始", L"2. 退出游戏" };
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < wcslen(options[i]); j++) {
            setBufferChar(20 + j, 10 + i, options[i][j], COLOR_CYAN);
        }
    }

    renderBuffer();

    // 输入处理保持不变
    int choice = safeInput(1, 2);
}

// 主函数（添加编码设置）
int main() {
    // 设置控制台编码和本地化
    system("chcp 65001 >nul");
    setlocale(LC_ALL, "");

    initConsoleBuffer();
    SetConsoleTitle(L"高级贪吃蛇游戏");
    system("mode con cols=100 lines=40");

    while (1) {
        welcomeScreen();
        int choice = safeInput(1, 3);
        switch (choice) {
        case 1: {
            initGame();
            while (game_running) {
                clearBuffer();

                createMap();
                drawSnake();
                setBufferChar(food.X, food.Y, L'★',
                    COLOR_YELLOW | FOREGROUND_INTENSITY);
                updateScore();

                renderBuffer();

                keyboardControl();
                moveSnake();
                checkCollision();
                Sleep(sleeptime);
            }
            gameOver();
            break;
        }
        case 2:
            showExplanation();
            break;
        case 3:
            saveScore();
            safeExit(EXIT_SUCCESS);
        }
    }
    return 0;
}
